package gui;

import java.awt.AWTException;
import java.awt.CheckboxMenuItem;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Menu;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.TrayIcon.MessageType;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Enumeration;

import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import net.glxn.qrgen.QRCode;
import net.glxn.qrgen.image.ImageType;
import server.IDFtpListener;
import server.IDHttpListener;
import server.IDInstance;
import server.IDServerListener;

public class Main implements IDServerListener
{
	private Thread httpServerThread = null;
	private Thread ftpServerThread = null;
	
	public BufferedImage createImage(String name)
	{
		try 
		{
			//File f = new File(getClass().getResource("/resources/" + name).toURI());
			return ImageIO.read(getClass().getResourceAsStream("/resources/" + name));
		} 
		catch (IOException e) 
		{
			return null;
		}
	}
	
	final PopupMenu popup;
    final TrayIcon trayIcon;
    final SystemTray tray;
    
    private boolean closeOnTransfer = false;

    private final void setCloseOnTransfer(boolean close)
    {
    	closeOnTransfer = close;
    }
    
    @SuppressWarnings("deprecation")
	private final void stopServer()
    {
    	if(httpServerThread.isAlive())
    	{
    		httpServerThread.stop();
    		if(trayIcon != null) trayIcon.displayMessage("InstaDir", "Server stopped.", MessageType.INFO);
    	}
    }
    
    private final void startServer()
    {
    	if(!httpServerThread.isAlive())
    	{
    		httpServerThread.start();
    		if(trayIcon != null) trayIcon.displayMessage("InstaDir", "Server started.", MessageType.INFO);
    	}
    }
    
    private final void exitServer()
    {
    	stopServer();
    	System.exit(0);
    }
    
    private final void copyURL()
    {
    	int port = httpServer.getPort();
    	if(port <= 0)
    	{
    		System.out.println("Server not running");
    		if(trayIcon != null) trayIcon.displayMessage("InstaDir", "Server is not currently running.", MessageType.WARNING);
    	}
    	else
    	{
    		if(myNets.size() == 0)
    		{
    			System.out.println("No net interfaces detected.");
    			if(trayIcon != null) trayIcon.displayMessage("InstaDir", "Couldn't get any IP addresses.", MessageType.WARNING);
    		}
    		else
    		{
    			NetIP nip = myNets.get(defIFace);
    			
    			String fullURL = "http://" + nip.IP + ":" + port + "/";
    			System.out.println(fullURL);
    			
    			StringSelection selection = new StringSelection(fullURL);
    		    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
    		    clipboard.setContents(selection, selection);
    			
    			if(trayIcon != null) trayIcon.displayMessage("InstaDir URL", fullURL, MessageType.INFO);
    		}
    	}
    }
    
    private final void showQR()
    {
    	int port = httpServer.getPort();
    	if(port <= 0)
    	{
    		System.out.println("Server not running");
    		if(trayIcon != null) trayIcon.displayMessage("InstaDir", "Server is not currently running.", MessageType.WARNING);
    	}
    	else
    	{
    		if(myNets.size() == 0)
    		{
    			System.out.println("No net interfaces detected.");
    			if(trayIcon != null) trayIcon.displayMessage("InstaDir", "Couldn't get any IP addresses.", MessageType.WARNING);
    		}
    		else
    		{
    			NetIP nip = myNets.get(defIFace);
    			
    			String fullURL = "http://" + nip.IP + ":" + port + "/";
    			System.out.println(fullURL);
    			
    			new QRDisplay(Util.generateQR(fullURL));
    		}
    	}
    }
    
    private AppWindow appWin = null;
    
    private final void showWindow()
    {
    	if(appWin == null)
    	{
    		appWin = new AppWindow(httpServer, this);
    	}
    	
    	appWin.setVisible(true);
    }
    
    //String[] myIPs;
    //
    public static class NetIP
    {
    	public String name = "";
    	public String desc = "";
    	public String IP = null;
    	public int ID = 0;
    	
    	public String toString()
    	{
    		return desc + " (" + name + "), IP = " + IP;
    	}
    }
    
    protected ArrayList<NetIP> myNets = new ArrayList<NetIP>();
    protected int defIFace = 0;
    
    private void enumerateNetInterfaces()
    {
		try 
		{
			myNets.clear();
			
			int id = 0;
			
			Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
			while(e.hasMoreElements())
	    	{
	    	    NetworkInterface n = (NetworkInterface) e.nextElement();
	    	    //System.out.println("Interface : " + n.getName());
	    	    if(n.getName().equals("lo")) continue;
	    	    
	    	    NetIP nip = new NetIP();
	    	    nip.name = n.getName();
	    	    nip.desc = n.getDisplayName();
	    	    
	    	    Enumeration<InetAddress> ee = n.getInetAddresses();
	    	    while (ee.hasMoreElements())
	    	    {
	    	        InetAddress i = (InetAddress) ee.nextElement();
	    	        String address = i.getHostAddress();
	    	        if(address.split("\\.").length == 4)
	    	        {
	    	        	nip.IP = address;
	    	        	break;
	    	        }
	    	    }
	    	    
	    	    if(nip.IP != null)
	    	    {
	    	    	nip.ID = id++;
	    	    	myNets.add(nip);
	    	    	System.out.println(nip);
	    	    }
	    	}
		} 
		catch (SocketException e1) 
		{
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
    	
    }
    
    final IDHttpListener httpServer;
    final IDFtpListener ftpServer;
    private boolean singleFileMode = false;
    
	public Main(String[] args)
	{
		IDInstance instance;
		String rootPath;
		if(args.length == 0)
		{
			rootPath = System.getProperty("user.dir");
			//rootPath = "/home/burek/Downloads/4.c";
		}
		else
		{
			rootPath = args[0];
		}
		
		instance = new IDInstance(rootPath, false);
		
		if(instance.getRoot() == null)
		{
			JOptionPane.showMessageDialog(null, "Invalid path given: '" + rootPath + "'", "Error", JOptionPane.ERROR_MESSAGE);
			System.exit(1);
			trayIcon = null;
			tray = null;
			httpServer = null;
			ftpServer = null;
			popup = null;
			return;
		}
		
		singleFileMode = instance.isSingleFile();
		
		closeOnTransfer = singleFileMode;
		
		httpServer = new IDHttpListener(instance);
		httpServer.setServerListener(this);
		
		ftpServer = new IDFtpListener(instance);
		ftpServer.setServerListener(this);
		
		enumerateNetInterfaces();
		
		if(SystemTray.isSupported())
		{
			popup = new PopupMenu();
			BufferedImage origImage = createImage("icons/icon-dark.png");
	        trayIcon = new TrayIcon(origImage);
	        tray = SystemTray.getSystemTray();
	        
	        if(instance.getRoot() != null)
	        	trayIcon.setToolTip(instance.getRoot().name);
	       
	        //trayIcon.setImageAutoSize(true);
	        
	        trayIcon.addActionListener(new ActionListener()
			{
				
				@Override
				public void actionPerformed(ActionEvent e)
				{
					showWindow();
					
				}
			});
	        
	        Dimension dim = tray.getTrayIconSize();
	        
	        if((int)dim.getWidth() != origImage.getWidth() || (int)dim.getHeight() != origImage.getHeight())
	        {
	        	BufferedImage resampled = Util.superResampleSimple(origImage, (int)dim.getWidth(), (int)dim.getHeight());
	        	trayIcon.setImage(resampled);
	        }
	        
	        // Create a pop-up menu components
	        MenuItem showItem = new MenuItem("Show window");
	        MenuItem urlItem = new MenuItem("Copy local URL to clipboard...");
	        MenuItem qrCodeItem = new MenuItem("Show local URL as QR-Code...");
	        MenuItem browserItem = new MenuItem("Open in browser...");
	        final CheckboxMenuItem cb1 = new CheckboxMenuItem("Close on transfer");
	        final Menu interfaceMenu = new Menu("Select network interface");
	        
	        MenuItem exitItem = new MenuItem("Exit");
	        
	        cb1.setState(closeOnTransfer);
	        
	        showItem.addActionListener(new ActionListener()
			{
				
				@Override
				public void actionPerformed(ActionEvent e)
				{
					showWindow();
				}
			});
	       
	        cb1.addItemListener(new ItemListener() {
				
				@Override
				public void itemStateChanged(ItemEvent e) 
				{
					setCloseOnTransfer(cb1.getState());
				}
			});
	        
	        exitItem.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent e) 
				{
					exitServer();
				}
			});
	        
	        urlItem.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent e) 
				{
					copyURL();
				}
			});
	        
	        qrCodeItem.addActionListener(new ActionListener()
			{
				
				@Override
				public void actionPerformed(ActionEvent e)
				{
					showQR();
				}
			});
	        
	        browserItem.addActionListener(new ActionListener()
			{
				
				@Override
				public void actionPerformed(ActionEvent e)
				{
					int port = httpServer.getPort();
					if(port > 0)
					{
						Desktop d = Desktop.getDesktop();
						try
						{
							d.browse(new URI("http://localhost:" + port + "/"));
						} 
						catch (IOException e1)
						{
							
						} 
						catch (URISyntaxException e1)
						{
							
						}
					}
					else
					{
						JOptionPane.showMessageDialog(null, "Server is not running.", "InstaDir", JOptionPane.ERROR_MESSAGE);
					}
				}
			});
	        
	        for(NetIP nip : myNets)
	        {
	        	final CheckboxMenuItem netCb = new CheckboxMenuItem(nip.toString());
	        	netCb.addItemListener(new ItemListener()
				{
					@Override
					public void itemStateChanged(ItemEvent e)
					{
						for(int i = 0; i < interfaceMenu.getItemCount(); ++i)
						{
							((CheckboxMenuItem)interfaceMenu.getItem(i)).setState(false);
							if(interfaceMenu.getItem(i) == e.getSource())
							{
								defIFace = i;
								//System.out.println("Default interface set to : " + i);
							}
						}
						
						((CheckboxMenuItem)e.getSource()).setState(true);
						
						//System.out.println("Does this happen?");
					}
				});
	        	interfaceMenu.add(netCb);
	        }
	        
	        if(interfaceMenu.getItem(0) != null)
	        {
	        	((CheckboxMenuItem)interfaceMenu.getItem(0)).setState(true);
	        }
	        
	        //Add components to pop-up menu
	        popup.add(showItem);
	        popup.addSeparator();
	        popup.add(urlItem);
	        popup.add(qrCodeItem);
	        popup.add(browserItem);
	        popup.addSeparator();
	        popup.add(cb1);
	        popup.add(interfaceMenu);
	        popup.addSeparator();
	        popup.add(exitItem);
	       
	        trayIcon.setPopupMenu(popup);
	        
	        
	       
	        try {
	            tray.add(trayIcon);
	        } catch (AWTException e) {
	            System.out.println("TrayIcon could not be added.");
	        }
		}
		else
		{
			popup = null;
			tray = null;
			trayIcon = null;
			System.out.println("System tray not supported, will not close main window.");
		}
		
		System.out.println("Server staring...");
		httpServerThread = new Thread(new Runnable() {
			
			@Override
			public void run() 
			{
				httpServer.startListening();
			}
		});
		
		httpServerThread.start();
		
		ftpServerThread = new Thread(new Runnable() {
			
			@Override
			public void run() 
			{
				ftpServer.startListening();
			}
		});
		
		ftpServerThread.start();
		
		//if(trayIcon != null) trayIcon.displayMessage("InstaDir", "Program is running, right click the icon for controls.", MessageType.INFO);
		System.out.println("Server started...");
		
		showWindow();
	}
	
	public static void main(String[] args) 
	{
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		new Main(args);

	}

	@Override
	public void transferStart(String srcIP, String path)
	{
		System.out.println("Transfer start!");
		System.out.println("IP   : " + srcIP);
		System.out.println("Path : " + path);
		
	}

	@Override
	public void transferEnd(String srcIP, String path)
	{
		System.out.println("Transfer end!");
		System.out.println("IP   : " + srcIP);
		System.out.println("Path : " + path);
		
		if(AppWindow.instance != null)
		{
			AppWindow.instance.addMessage("File \"" + path + "\" downloaded from " + srcIP);
		}
		
		if(singleFileMode && closeOnTransfer)
		{
			if(trayIcon != null)
			{
				trayIcon.displayMessage("InstaDir", "Transfer complete, server is shutting down now.", MessageType.INFO);
				try
				{
					Thread.sleep(2000);
				} 
				catch (InterruptedException e) { }
			}
			System.out.println("Autoshutdown...");
			System.exit(0);
		}
	}

}
